package com.yunfei.commonbase.hdutil;


import com.jcraft.jsch.*;

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import java.util.Vector;
import java.util.logging.Logger;

public class SFTPUtils {

    private static final Logger logger = Logger.getLogger(SFTPUtils.class.toString());

    /**
     * 连接sftp服务器
     *
     * @param ftpHostIp ftp主机ip
     * @param ftpPort   ftp端口
     * @param userName  ftp用户名
     * @param password  ftp密码
     * @param timeOut   超时时间（单位毫秒）
     * @return
     */
    public static ChannelSftp getSftpClient(String ftpHostIp, int ftpPort, String userName, String password,
                                            int timeOut) throws Exception {
        ChannelSftp sftp = null;
        try {
            JSch jsch = new JSch();
            Session sshSession = jsch.getSession(userName, ftpHostIp, ftpPort);
            sshSession.setPassword(password);
            Properties sshConfig = new Properties();
            sshConfig.put("StrictHostKeyChecking", "no");
            sshSession.setConfig(sshConfig);
            sshSession.setTimeout(timeOut);
            sshSession.connect();
            Channel channel = sshSession.openChannel("sftp");
            channel.connect();
            sftp = (ChannelSftp) channel;
            logger.info("Connected to " + ftpHostIp + ".");
        } catch (Exception e) {
            e.printStackTrace();
            throw new Exception(e);
        }
        return sftp;
    }

    /**
     * 关闭sftp服务器
     *
     * @param sftp
     * @throws Exception
     */
    public static void closeSftpClient(ChannelSftp sftp) throws Exception {
        try {
            Session sftpSession = sftp.getSession();
            // 关闭连接
            if (sftp.isConnected()) {
                sftp.disconnect();
            }
            // 关闭session
            if (sftpSession != null) {
                sftpSession.disconnect();
            }
        } catch (JSchException e) {
            e.printStackTrace();
            throw new Exception("sftp 关闭连接失败");
        }
    }

    /**
     * 创建目录
     *
     * @param dir  目录名称
     * @param sftp
     */
    private static void createDir(String dir, ChannelSftp sftp) throws Exception {
        try {
            // 文件服务器是linux，写死了/
            String[] dirArr = dir.split("/");
            for (String tmpDir : dirArr) {
                if (null == tmpDir || "".equals(tmpDir))
                    continue;
                try {
                    sftp.cd(tmpDir);
                    System.out.println(sftp.pwd());
                } catch (SftpException e) {
                    logger.info("目录不存在，需要创建，异常就不打印了。。。");
                    // 创建一个目录并cd到那个目录下面，为了下一次
                    sftp.mkdir(tmpDir);
                    sftp.cd(tmpDir);
                }
            }
        } catch (SftpException e) {
            e.printStackTrace();
            throw new Exception("创建目录失败了:" + e.getMessage());
        }

    }

//    public static void main(String[] args) throws Exception {
//        File file = new File("D:\\aa.txt");
//        upload("192.168.1.138",22,"sftp","sftp",5000,new FileInputStream(file),
//                "/home/sftp/mysftp/upload/yf","aa.tct");
//    }


    public static void main(String[] args) throws Exception {
//        ChannelSftp sftp = getSftpClient(host, port, username, password,5000);
        InputStream is = new FileInputStream(new File("D:\\aa.txt"));
        upload(host, port, username, password, 50000, is, "/upload/yf", "HE-1-ZW-Focus5C-20201027.csv");

    }

    /**
     * 上传
     *
     * @param fis         源文件输入流
     * @param dir         路径
     * @param newFileName 新文件名
     * @return
     */
    public static void upload(String ftpHostIp, int ftpPort, String userName, String password,
                              int timeOut, InputStream fis, String dir, String newFileName) throws Exception {
        // 获取sftp客户端连接
        ChannelSftp sftp = getSftpClient(ftpHostIp, ftpPort, userName, password, timeOut);
        try {
            // 切换到/目录
            sftp.cd(sftp.getHome());
            System.out.println(sftp.pwd());
            // 因为创建目录的时候，已经切换到对应的目录了，所以不创建目录后不再需要cd
            createDir(dir, sftp);
            sftp.put(fis, newFileName);
        } catch (Exception e) {
            logger.info("sftp文件上传失败。。。");
            e.printStackTrace();
            throw new Exception("sftp文件上传失败:" + e.getMessage());
        } finally {
            closeSftpClient(sftp);
        }
    }

    /**
     * 下载
     *
     * @param os       输出流
     * @param fileName 带路径的文件名
     * @return
     */
    public static void download(String ftpHostIp, int ftpPort, String userName, String password, int timeOut,
                                OutputStream os, String fileName) throws Exception {
        // 获取sftp客户端连接
        ChannelSftp sftp = getSftpClient(ftpHostIp, ftpPort, userName, password, timeOut);
        try {
            // 切换到家目录
            sftp.cd(sftp.getHome());
            sftp.get(fileName, os);
        } catch (Exception e) {
            e.printStackTrace();
            throw new Exception("sftp文件下载失败:" + e.getMessage());
        } finally {
            closeSftpClient(sftp);
        }
    }

    /**
     * 删除文件
     *
     * @param fileName 文件名含路径（相对路径）
     * @return
     */
    public static boolean deleteFile(String ftpHostIp, int ftpPort, String userName, String password, int timeOut,
                                     String fileName) throws Exception {
        // 获取sftp客户端连接
        ChannelSftp sftp = getSftpClient(ftpHostIp, ftpPort, userName, password, timeOut);
        boolean flag = true;
        try {
            // 切换到家目录
            sftp.cd(sftp.getHome());
            sftp.rm(fileName);
        } catch (Exception e) {
            logger.info("sftp文件删除失败。。。");
            flag = false;
            e.printStackTrace();
        } finally {
            closeSftpClient(sftp);
        }
        return flag;
    }


    /**
     * 列出目录下的文件
     *
     * @param directory
     *            要列出的目录
     * @param ftpHostIp
     * @return
     * @throws SftpException
     */
    public static List<String> listFiles(String ftpHostIp, int ftpPort, String userName, String password, int timeOut,String directory)
            throws Exception {
        // 获取sftp客户端连接
        ChannelSftp sftp = getSftpClient(ftpHostIp, ftpPort, userName, password, timeOut);
        List<String> fileListName = new ArrayList<>();
        getListFilesName(sftp,directory,fileListName);
        return fileListName;
    }

    public static void  getListFilesName(ChannelSftp sftp,String directory,List<String> fileListName) throws SftpException {
        Vector<String> files = sftp.ls(directory);
        for (int i = 0; i < files.size(); i++) {
            Object obj = files.elementAt(i);
            if (obj instanceof com.jcraft.jsch.ChannelSftp.LsEntry) {
                ChannelSftp.LsEntry entry = (ChannelSftp.LsEntry) obj;
                if (!entry.getAttrs().isDir()) {
                    fileListName.add(directory+"/"+entry.getFilename());
                }
                if (entry.getAttrs().isDir()) {
                    if (!entry.getFilename().equals(".") && !entry.getFilename().equals("..")) {
                        getListFilesName(sftp,directory+"/"+entry.getFilename(),fileListName);
                    }
                }
            }
        }
    }


    public static void deleteAllSFTPFile(String ftpHostIp, int ftpPort, String userName, String password, int timeOut,String directory){
        try{
            // 获取sftp客户端连接
            ChannelSftp sftp = getSftpClient(ftpHostIp, ftpPort, userName, password, timeOut);
            deleteSFTP(sftp,directory);
        }catch (Exception e){

        }
    }

    public static void deleteSFTP(ChannelSftp sftp, String directory) throws Exception {
        try {
            if (!isDirExist(directory, sftp)) {
                throw new Exception("文件夹 " + directory + " 不存在");
            }

            Vector<ChannelSftp.LsEntry> vector = sftp.ls(directory);
            if (vector.size() == 1) { // 文件，直接删除
                // sftp.rm(directory);
            } else if (vector.size() == 2) { // 空文件夹，直接删除
                // sftp.rmdir(directory);
            } else {
                String fileName;
                // 删除文件夹下所有文件
                for (ChannelSftp.LsEntry en : vector) {
                    fileName = en.getFilename();
                    if (".".equals(fileName) || "..".equals(fileName)) {
                    } else {
                        if (!isExistDir(directory + "/" + fileName, sftp)) {
                            SftpATTRS attrs = sftp.stat(directory + "/" + fileName);
                            //if (DateUtils.addHours(new Date(attrs.getATime() * 1000L), hours).before(new Date())) {
                                sftp.rm(directory + "/" + fileName);
                                logger.info("delete file success");
                            //}
                        } else if (isDirExist(directory + "/" + fileName, sftp)) {
                            String childPath = directory + "/" + fileName;
                            deleteSFTP(sftp, childPath);
                        }
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new Exception("删除sftp文件失败");
        }
    }

    public static boolean isDirExist(String directory, ChannelSftp sftp) {
        try {
            Vector<?> vector = sftp.ls(directory);
            return null != vector;
        } catch (Exception e) {
            return false;
        }
    }

    public static boolean isExistDir(String path, ChannelSftp sftp) {
        boolean isExist = false;
        try {
            SftpATTRS sftpATTRS = sftp.lstat(path);
            isExist = true;
            return sftpATTRS.isDir();
        } catch (Exception e) {
            if (e.getMessage().toLowerCase().equals("no such file")) {
                isExist = false;
            }
        }
        return isExist;
    }

    private static String host = "192.168.1.138";
    private static Integer port = 22;
    private static String username = "sftp";
    private static String password = "sftp";

}
